﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Nvigorate.Data;
using Nvigorate.Test.Comparer;
using Nvigorate.Test.Data.Doubles;

namespace Nvigorate.Test.Data
{
    /// <summary>
    /// Summary description for DataInterfaceTests
    /// </summary>
    [TestClass]
    public class DataInterfaceTests : DataTestBase
    {
        #region ExecuteCommand tests

        [TestMethod]
        public void ExecuteCommand_NoParameters_ConfiguresCommandAndCallsExecute()
        {
            // Arrange
            var commandText = "DELETE FROM Employee";
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var command = new TestDatabaseCommand(commandText, provider.Object);
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.ExecuteCommand(commandText, false);

            // Assert
            Assert.AreEqual(0, command.Parameters.Count);
            Assert.AreEqual(CONN_STRING, command.ConnectionString);
            Assert.AreEqual(commandText, command.CommandText);
            Assert.IsFalse(command.UseTransactionScope);
            Assert.AreEqual(1, command.ExecuteCalledCount);
        }

        [TestMethod]
        public void ExecuteCommand_NoParametersStoredProc_ConfiguresCommandAndCallsExecute()
        {
            // Arrange
            var commandText = "spDeleteEmployee";
            var connection = CreateConnection();

            var provider = CreateProvider(commandText, connection.Object);
            var commandFactory = CreateCommandFactory(provider.Object);
            var command = new TestDatabaseCommand(commandText, provider.Object);
            commandFactory.Expect(f => f.GetCommand(commandText, provider.Object, It.IsAny<int>(),
                                        It.IsAny<DataTable>())).Returns(command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.AddProcedure(commandText);
            dataInterface.ExecuteCommand(commandText, false);

            // Assert
            Assert.AreEqual(0, command.Parameters.Count);
            Assert.AreEqual(CONN_STRING, connection.Object.ConnectionString);
            Assert.AreEqual(commandText, command.CommandText);
            Assert.AreEqual(1, command.ExecuteCalledCount);

        }

        [TestMethod]
        public void ExecuteCommand_ListParameters_ConfiguresCommandAndCallsExecute()
        {
            // Arrange
            var commandText = "DELETE FROM Employee";
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var command = new TestDatabaseCommand(commandText, provider.Object);
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            var parameters = new List<IDbDataParameter>
                                 {
                                     CreateParameter("@param1", 1).Object,
                                     CreateParameter("@param2", 2).Object
                                 };

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.ExecuteCommand(commandText, false, parameters);

            // Assert
            var comparer = new DbDataParameterEqualityComparer();

            Assert.IsTrue(comparer.Equals(CreateParameter("@param1", 1).Object, command["@param1"]));
            Assert.IsTrue(comparer.Equals(CreateParameter("@param2", 2).Object, command["@param2"]));
            Assert.AreEqual(CONN_STRING, command.ConnectionString);
            Assert.AreEqual(commandText, command.CommandText);
            Assert.IsFalse(command.UseTransactionScope);
            Assert.AreEqual(1, command.ExecuteCalledCount);
        }

        [TestMethod]
        public void ExecuteCommand_DictionaryParameters_ConfiguresCommandAndCallsExecute()
        {
            // Arrange
            var commandText = "DELETE FROM Employee";
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var parameters = new Dictionary<string, object>
                                 {
                                     {"@param1", 1},
                                     {"@param2", 2}
                                 };

            provider.ExpectGetParameters(parameters, this);

            var command = new TestDatabaseCommand(commandText, provider.Object);
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.ExecuteCommand(commandText, false, parameters);

            // Assert
            var comparer = new DbDataParameterEqualityComparer();
            Assert.IsTrue(comparer.Equals(CreateParameter("@param1", 1).Object, command["@param1"]));
            Assert.IsTrue(comparer.Equals(CreateParameter("@param2", 2).Object, command["@param2"]));
            Assert.AreEqual(CONN_STRING, command.ConnectionString);
            Assert.AreEqual(commandText, command.CommandText);
            Assert.IsFalse(command.UseTransactionScope);
            Assert.AreEqual(1, command.ExecuteCalledCount);
        }

        [TestMethod]
        public void ExecuteCommand_ObjectArrayParameters_ConfiguresCommandAndCallsExecute()
        {
            // Arrange
            var commandText = "spDeleteEmployee";
            var connection = CreateConnection();

            var provider = CreateProvider(commandText, connection.Object);

            var paramValue1 = 1;
            var paramValue2 = "param2";
            var param1 = CreateParameter("@param1");
            var param2 = CreateParameter("@param2");

            var commandFactory = CreateCommandFactory(provider.Object);
            var command = new TestDatabaseCommand(commandText, provider.Object, new[] {param1.Object, param2.Object});
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.AddProcedure(commandText, param1.Object, param2.Object);
            dataInterface.ExecuteCommand(commandText, false, paramValue1, paramValue2);

            // Assert
            var comparer = new DbDataParameterEqualityComparer();
            Assert.IsTrue(comparer.Equals(CreateParameter("@param1", paramValue1).Object, command["@param1"]));
            Assert.IsTrue(comparer.Equals(CreateParameter("@param2", paramValue2).Object, command["@param2"]));
            Assert.AreEqual(CONN_STRING, connection.Object.ConnectionString);
            Assert.AreEqual(commandText, command.CommandText);
            Assert.AreEqual(1, command.ExecuteCalledCount);
        }

        [TestMethod, ExpectedException(typeof(DataInterfaceException))]
        public void ExecuteCommand_ObjectArrayParametersProcedureNotAdded_ThrowsException()
        {
            // Arrange
            var commandText = "spDeleteEmployee";
            var connection = CreateConnection();

            var provider = CreateProvider(commandText, connection.Object);

            var paramValue1 = 1;
            var paramValue2 = "param2";
            var param1 = CreateParameter("@param1");
            var param2 = CreateParameter("@param2");

            var commandFactory = CreateCommandFactory(provider.Object);
            var command = new TestDatabaseCommand(commandText, provider.Object, new[] { param1.Object, param2.Object });
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.ExecuteCommand(commandText, false, paramValue1, paramValue2);
            
        }

        [TestMethod]
        public void ExecuteCommand_NoTransaction_ConfiguresCommandAndCallsExecute()
        {
            // Arrange
            var commandText = "DELETE FROM Employee";
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var command = new TestDatabaseCommand(commandText, provider.Object);
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.ExecuteCommand(commandText, false);

            // Assert
            Assert.IsFalse(command.UseTransactionScope);
        }

        [TestMethod]
        public void ExecuteCommand_UseTransaction_ConfiguresCommandAndCallsExecute()
        {
            // Arrange
            var commandText = "DELETE FROM Employee";
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var command = new TestDatabaseCommand(commandText, provider.Object);
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.ExecuteCommand(commandText, true);

            // Assert
            Assert.IsTrue(command.UseTransactionScope);
        }

        #endregion

        #region GetTable tests

        [TestMethod]
        public void GetTable_NoParameters_ConfiguresCommandAndCallsGetDataTable()
        {
            // Arrange
            var commandText = "SELECT * FROM Employee";
            var tableName = "Employee";
            var connection = CreateConnection();

            var provider = CreateProvider(commandText, connection.Object);

            var command = new TestDatabaseCommand(commandText, provider.Object);
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.GetTable(commandText, tableName);

            // Assert
            Assert.AreEqual(0, command.Parameters.Count);
            Assert.AreEqual(CONN_STRING, command.ConnectionString);
            Assert.AreEqual(commandText, command.CommandText);
            Assert.AreEqual(1, command.GetTableCalledCount);
        }

        [TestMethod]
        public void GetTable_ListParameters_ConfiguresCommandAndCallsGetDataTable()
        {
            // Arrange
            var commandText = "SELECT * FROM Employee";
            var tableName = "Employee";
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var command = new TestDatabaseCommand(commandText, provider.Object);
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            var parameters = new List<IDbDataParameter>
                                 {
                                     CreateParameter("@param1", 1).Object,
                                     CreateParameter("@param2", 2).Object
                                 };

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            var actual = dataInterface.GetTable(commandText, tableName, parameters);

            // Assert
            var comparer = new DbDataParameterEqualityComparer();
            Assert.IsTrue(comparer.Equals(parameters[0], command["@param1"]));
            Assert.IsTrue(comparer.Equals(parameters[1], command["@param2"]));
            Assert.AreEqual(CONN_STRING, command.ConnectionString);
            Assert.AreEqual(tableName, actual.TableName);
            Assert.AreEqual(commandText, command.CommandText);
            Assert.AreEqual(1, command.GetTableCalledCount);
        }

        [TestMethod]
        public void GetTable_DictionaryParameters_ConfiguresCommandAndCallsGetDataTable()
        {
            // Arrange
            var commandText = "SELECT * FROM Employee";
            var tableName = "Employee";
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var parameters = new Dictionary<string, object>
                                 {
                                     {"@param1", 1},
                                     {"@param2", 2}
                                 };

            provider.ExpectGetParameters(parameters, this);

            var command = new TestDatabaseCommand(commandText, provider.Object);
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);


            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            var actual = dataInterface.GetTable(commandText, tableName, parameters);

            // Assert
            var comparer = new DbDataParameterEqualityComparer();
            Assert.IsTrue(comparer.Equals(CreateParameter("@param1", 1).Object, command["@param1"]));
            Assert.IsTrue(comparer.Equals(CreateParameter("@param2", 2).Object, command["@param2"]));
            Assert.AreEqual(CONN_STRING, command.ConnectionString);
            Assert.AreEqual(tableName, actual.TableName);
            Assert.AreEqual(commandText, command.CommandText);
            Assert.AreEqual(1, command.GetTableCalledCount);
        }

        [TestMethod]
        public void GetTable_ObjectArrayParameters_ConfiguresCommandAndCallsGetDataTable()
        {
            // Arrange
            var commandText = "spGetEmployees";
            var tableName = "Employee";
            var connection = CreateConnection();

            var provider = CreateProvider(commandText, connection.Object);

            var paramValue1 = 1;
            var paramValue2 = "param2";
            var param1 = CreateParameter("@param1");
            var param2 = CreateParameter("@param2");

            var commandFactory = CreateCommandFactory(provider.Object);
            var command = new TestDatabaseCommand(commandText, provider.Object, new[] {param1.Object, param2.Object});
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.AddProcedure(commandText, param1.Object, param2.Object);
            var actual = dataInterface.GetTable(commandText, tableName, paramValue1, paramValue2);

            // Assert
            var comparer = new DbDataParameterEqualityComparer();
            Assert.IsTrue(comparer.Equals(CreateParameter("@param1", paramValue1).Object, command["@param1"]));
            Assert.IsTrue(comparer.Equals(CreateParameter("@param2", paramValue2).Object, command["@param2"]));
            Assert.AreEqual(CONN_STRING, connection.Object.ConnectionString);
            Assert.AreEqual(tableName, actual.TableName);
            Assert.AreEqual(commandText, command.CommandText);
            Assert.AreEqual(1, command.GetTableCalledCount);
        }

        #endregion

        #region GetSet Tests

        [TestMethod]
        public void GetSet_NoParameters_ConfiguresCommandAndCallsGetDataSet()
        {
            // Arrange
            var commandText = "SELECT * FROM Employee";
            var dataSetName = "Employee";
            var tableNames = new List<string> {"ContactInfo", "JobInfo"};
            var connection = CreateConnection();

            var provider = CreateProvider(commandText, connection.Object);

            var command = new TestDatabaseCommand(commandText, provider.Object);
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            var actual = dataInterface.GetSet(commandText, dataSetName, tableNames);

            // Assert
            Assert.AreEqual(0, command.Parameters.Count);
            Assert.AreEqual(CONN_STRING, command.ConnectionString);
            Assert.AreEqual(dataSetName, actual.DataSetName);
            Assert.AreEqual(tableNames.Count, actual.Tables.Count);
            Assert.IsTrue(tableNames.TrueForAll(t => actual.Tables[t] != null));
            Assert.AreEqual(commandText, command.CommandText);
            Assert.AreEqual(1, command.GetDataSetCalledCount);
        }

        [TestMethod]
        public void GetSet_ListParameters_ConfiguresCommandAndCallsGetDataSet()
        {
            // Arrange
            var commandText = "SELECT * FROM Employee";
            var dataSetName = "Employee";
            var tableNames = new List<string> {"ContactInfo", "JobInfo"};
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var command = new TestDatabaseCommand(commandText, provider.Object);
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            var parameters = new List<IDbDataParameter>
                                 {
                                     CreateParameter("@param1", 1).Object,
                                     CreateParameter("@param2", 2).Object
                                 };

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            var actual = dataInterface.GetSet(commandText, dataSetName, tableNames, parameters);

            // Assert
            var comparer = new DbDataParameterEqualityComparer();
            Assert.IsTrue(comparer.Equals(CreateParameter("@param1", 1).Object, command["@param1"]));
            Assert.IsTrue(comparer.Equals(CreateParameter("@param2", 2).Object, command["@param2"]));
            Assert.AreEqual(CONN_STRING, command.ConnectionString);
            Assert.AreEqual(dataSetName, actual.DataSetName);
            Assert.AreEqual(tableNames.Count, actual.Tables.Count);
            Assert.IsTrue(tableNames.TrueForAll(t => actual.Tables[t] != null));
            Assert.AreEqual(commandText, command.CommandText);
            Assert.AreEqual(1, command.GetDataSetCalledCount);
        }

        [TestMethod]
        public void GetSet_DictionaryParameters_ConfiguresCommandAndCallsGetDataSet()
        {
            // Arrange
            var commandText = "SELECT * FROM Employee";
            var dataSetName = "Employee";
            var tableNames = new List<string> {"ContactInfo", "JobInfo"};
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var parameters = new Dictionary<string, object>
                                 {
                                     {"@param1", 1},
                                     {"@param2", 2}
                                 };

            provider.ExpectGetParameters(parameters, this);

            var command = new TestDatabaseCommand(commandText, provider.Object);
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            var actual = dataInterface.GetSet(commandText, dataSetName, tableNames, parameters);

            // Assert
            var comparer = new DbDataParameterEqualityComparer();
            Assert.IsTrue(comparer.Equals(CreateParameter("@param1", 1).Object, command["@param1"]));
            Assert.IsTrue(comparer.Equals(CreateParameter("@param2", 2).Object, command["@param2"]));
            Assert.AreEqual(CONN_STRING, command.ConnectionString);
            Assert.AreEqual(dataSetName, actual.DataSetName);
            Assert.AreEqual(tableNames.Count, actual.Tables.Count);
            Assert.IsTrue(tableNames.TrueForAll(t => actual.Tables[t] != null));
            Assert.AreEqual(commandText, command.CommandText);
            Assert.AreEqual(1, command.GetDataSetCalledCount);
        }

        [TestMethod]
        public void GetSet_ObjectArrayParameters_ConfiguresCommandAndCallsGetDataSet()
        {
            // Arrange
            var commandText = "spGetEmployees";
            var dataSetName = "Employee";
            var tableNames = new List<string> {"ContactInfo", "JobInfo"};
            var connection = CreateConnection();

            var provider = CreateProvider(commandText, connection.Object);

            var paramValue1 = 1;
            var paramValue2 = "param2";
            var param1 = CreateParameter("@param1");
            var param2 = CreateParameter("@param2");

            var commandFactory = CreateCommandFactory(provider.Object);
            var command = new TestDatabaseCommand(commandText, provider.Object, new[] {param1.Object, param2.Object});
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.AddProcedure(commandText, param1.Object, param2.Object);
            var actual = dataInterface.GetSet(commandText, dataSetName, tableNames, paramValue1, paramValue2);

            // Assert
            var comparer = new DbDataParameterEqualityComparer();
            Assert.IsTrue(comparer.Equals(CreateParameter("@param1", 1).Object, command["@param1"]));
            Assert.IsTrue(comparer.Equals(CreateParameter("@param2", "param2").Object, command["@param2"]));
            Assert.AreEqual(CONN_STRING, command.ConnectionString);
            Assert.AreEqual(dataSetName, actual.DataSetName);
            Assert.AreEqual(tableNames.Count, actual.Tables.Count);
            Assert.IsTrue(tableNames.TrueForAll(t => actual.Tables[t] != null));
            Assert.AreEqual(commandText, command.CommandText);
            Assert.AreEqual(1, command.GetDataSetCalledCount);
        }

        #endregion

        #region GetValue Tests

        [TestMethod]
        public void GetValue_NoParameters_ConfiguresCommandAndCallsGetScalar()
        {
            // Arrange
            var commandText = "SELECT Id FROM Employee WHERE Name = 'test'";
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var command = new TestDatabaseCommand(commandText, provider.Object) {ReturnValue = "ID1"};
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            var actual = dataInterface.GetValue(commandText);

            // Assert
            Assert.AreEqual(0, command.Parameters.Count);
            Assert.AreEqual("ID1", actual);
            Assert.AreEqual(CONN_STRING, command.ConnectionString);
            Assert.AreEqual(commandText, command.CommandText);
            Assert.AreEqual(1, command.GetScalarCalledCount);
        }

        [TestMethod]
        public void GetValue_ListParameters_ConfiguresCommandAndCallsGetScalar()
        {
            // Arrange
            var commandText = "SELECT Id FROM Employee WHERE Name = 'test'";
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var command = new TestDatabaseCommand(commandText, provider.Object) {ReturnValue = "ID1"};
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            var parameters = new List<IDbDataParameter>
                                 {
                                     CreateParameter("@param1", 1).Object,
                                     CreateParameter("@param2", 2).Object
                                 };
            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            var actual = dataInterface.GetValue(commandText, parameters);

            // Assert
            var comparer = new DbDataParameterEqualityComparer();
            Assert.IsTrue(comparer.Equals(CreateParameter("@param1", 1).Object, command["@param1"]));
            Assert.IsTrue(comparer.Equals(CreateParameter("@param2", 2).Object, command["@param2"]));
            Assert.AreEqual("ID1", actual);
            Assert.AreEqual(CONN_STRING, command.ConnectionString);
            Assert.AreEqual(commandText, command.CommandText);
            Assert.AreEqual(1, command.GetScalarCalledCount);
        }

        [TestMethod]
        public void GetValue_DictionaryParameters_ConfiguresCommandAndCallsGetScalar()
        {
            // Arrange
            var commandText = "SELECT Id FROM Employee WHERE Name = 'test'";
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var parameters = new Dictionary<string, object>
                                 {
                                     {"@param1", 1},
                                     {"@param2", 2}
                                 };
            provider.ExpectGetParameters(parameters, this);

            var command = new TestDatabaseCommand(commandText, provider.Object) {ReturnValue = "ID1"};
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            var actual = dataInterface.GetValue(commandText, parameters);

            // Assert
            var comparer = new DbDataParameterEqualityComparer();
            Assert.IsTrue(comparer.Equals(CreateParameter("@param1", 1).Object, command["@param1"]));
            Assert.IsTrue(comparer.Equals(CreateParameter("@param2", 2).Object, command["@param2"]));
            Assert.AreEqual("ID1", actual);
            Assert.AreEqual(CONN_STRING, command.ConnectionString);
            Assert.AreEqual(commandText, command.CommandText);
            Assert.AreEqual(1, command.GetScalarCalledCount);
        }

        [TestMethod]
        public void GetValue_ObjectArrayParameters_ConfiguresCommandAndCallsGetScalar()
        {
            // Arrange
            var commandText = "spGetEmployees";
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var paramValue1 = 1;
            var paramValue2 = "param2";
            var param1 = CreateParameter("@param1");
            var param2 = CreateParameter("@param2");

            var commandFactory = CreateCommandFactory(provider.Object);
            var command = new TestDatabaseCommand(commandText, provider.Object, new[] {param1.Object, param2.Object})
                              {
                                  ReturnValue = "ID1"
                              };
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.AddProcedure(commandText, param1.Object, param2.Object);
            var actual = dataInterface.GetValue(commandText, paramValue1, paramValue2);

            // Assert
            var comparer = new DbDataParameterEqualityComparer();
            Assert.IsTrue(comparer.Equals(CreateParameter("@param1", 1).Object, command["@param1"]));
            Assert.IsTrue(comparer.Equals(CreateParameter("@param2", "param2").Object, command["@param2"]));
            Assert.AreEqual("ID1", actual);
            Assert.AreEqual(CONN_STRING, command.ConnectionString);
            Assert.AreEqual(commandText, command.CommandText);
            Assert.AreEqual(1, command.GetScalarCalledCount);
        }

        #endregion

        #region AddProcedure Tests

        [TestMethod]
        public void AddProcedure_ProcedureNotAdded_AddsProcedureWithNoParameters()
        {
            // Arrange
            var commandText = "spTestProcedure";
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var command = new TestDatabaseCommand(commandText, provider.Object);

            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.Expect(f => f.GetCommand(commandText, provider.Object, It.IsAny<int>(),
                                                    It.IsAny<DataTable>())).Returns(command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.AddProcedure(commandText);
            dataInterface.ExecuteCommand(commandText, false);

            // Assert
            Assert.AreEqual(commandText, command.CommandText);
        }

        [TestMethod]
        public void AddProcedure_ProcedureNotAdded_AddsProcedureWithParameters()
        {
            // Arrange
            var commandText = "spTestProcedure";
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);

            var command = new TestDatabaseCommand(commandText, provider.Object,
                                                  new[]
                                                      {
                                                          CreateParameter("@param1").
                                                              Object,
                                                          CreateParameter("@param2").
                                                              Object
                                                      });
            var commandFactory = CreateCommandFactory(provider.Object);
            commandFactory.ExpectGetCommand(commandText, provider.Object, command);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.AddProcedure(commandText, CreateParameter("@param1").Object,
                                       CreateParameter("@param2").Object);
            dataInterface.ExecuteCommand(commandText, false, 1, 2);

            // Assert
            var comparer = new DbDataParameterEqualityComparer();
            Assert.IsTrue(comparer.Equals(CreateParameter("@param1", 1).Object, command["@param1"]));
            Assert.IsTrue(comparer.Equals(CreateParameter("@param2", 2).Object, command["@param2"]));
            Assert.AreEqual(commandText, command.CommandText);
        }

        #endregion

        #region AddAllProcedures Tests

        [TestMethod]
        public void AddAllProcedures_ProcedureIsExecuted()
        {
            // Arrange
            var commandText = "spGetEmployee";
            var connection = CreateConnection();
            var provider = CreateProvider(commandText, connection.Object);
            var commandFactory = CreateCommandFactory(provider.Object);

            var resultSet = CreateAllProcsDataSet();
            resultSet.Tables["procs"].Rows.Add(new object[] {commandText});

            var command = new TestDatabaseCommand(provider.Object.GetParamsForAllProceduresCommand(), provider.Object)
                              {ResultSet = resultSet};
            
            commandFactory.ExpectGetCommand(GET_ALL_PROC_COMMAND, provider.Object, command);

            // Add proc that will be loaded during AddAllProcedures
            var procCommand = new Mock<IDatabaseCommand>();
            procCommand.Expect(c => c.Execute(It.IsAny<IDbConnection>(), It.IsAny<bool>())).Returns(5);
            commandFactory.ExpectGetCommand(commandText, provider.Object, procCommand.Object);

            // Act
            var dataInterface = new DataInterface(connection.Object, provider.Object, commandFactory.Object);
            dataInterface.AddAllProcedures();
            var actual = dataInterface.ExecuteCommand("spGetEmployee", false);

            // Assert
            Assert.AreEqual(5, actual);
            
        }
        #endregion

        [TestMethod]
        public void TestCustomError()
        {
            var database = new DataInterface(ConfigurationManager.ConnectionStrings["simple"]);
            try
            {
                database.ExecuteCommand("RAISERROR('SHIT', 14, 14)", false);
            }
            catch (ConcurrencyException ce)
            {
                Console.WriteLine(ce);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }   
    }
}